package com.br.aiops.alert.message;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.br.aiops.alert.AlertData;
import com.br.aiops.counter.AlertLogCounter;
import com.br.aiops.rule.Rule;
import com.br.aiops.schedule.Schedules;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.Formatter;
import java.util.Map;
import java.util.Objects;

@Data
public class AlertMessage {

    private static final Logger LOGGER = LoggerFactory.getLogger(AlertMessage.class);
    public static final String RESUME_PROBLEM = "PROBLEM";
    public static final String RESUME_OK = "OK";
    public static final String ALERT_APP_TYPE_LOG = "log";
    public static final String ALERT_HARDWARE_TYPE_APP = "app";
    public static final String EMPTY = "";

    /**
     * alertname + （共多少条）
     */
    private String title;
    private String alertName;
    private String level;
    private String service;
    private String hosts;
    private String pods;
    private long allPodCount;
    private long errorPodCount;
    private long allNodeCount;
    private long errorNodeCount;
    private String errorCode;
    private String message;

    private String startTime;
    private String updateTime;
    //如果为空代表没有恢复
    private String resumeDate;
    /**
     * 该周期内的告警次数
     */
    private long alertTimesInAllCycle;

    /**
     * 调度周期内的告警次数
     */
    private long alertTimesInSchedule;

    /**
     * 告警负责人
     */
    private String owner;

    /**
     * 匹配的规则
     */
    private Rule rule;

    private AlertMessage(AlertLogCounter counter, String owner) {
        this(counter, owner, null);
    }

    private AlertMessage(AlertLogCounter counter,String owner, Date resumeDate) {
        this.title = counter.getAlertLog().getAlertName() + "(共" + counter.getAlertTimesInAllCycle() + "条)";
        this.alertName = counter.getAlertLog().getAlertName();
        this.level = counter.getRule().getAlertLevel(); //使用规则的级别
        this.service = counter.getAlertLog().getService();
        this.hosts = String.join(",", counter.getHosts());
        this.pods = String.join(",", counter.getPods());
        this.errorPodCount = counter.getPods().parallelStream().count();
        this.allPodCount = counter.getAllPods().parallelStream().count();
        this.errorNodeCount = counter.getHosts().parallelStream().count();
        this.allNodeCount = counter.getAllPods().parallelStream().map(o -> ((JSONObject)o).getString("node")).distinct().count();
        this.errorCode = counter.getAlertLog().getErrorCode();
        this.message = counter.getAlertLog().getMessage();
        this.startTime = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss").format(counter.getStartTime());
        this.updateTime = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss").format(counter.getUpdateTime());
        this.alertTimesInAllCycle = counter.getAlertTimesInAllCycle().get();
        this.alertTimesInSchedule = Schedules.getSchedule(counter.getRule().getDuration()).getCount(counter);
        this.owner = owner;
        this.rule = counter.getRule();
        if (Objects.nonNull(resumeDate)) {
            this.resumeDate = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss").format(resumeDate);
        }
    }

    public static String buildAlertMessage(AlertLogCounter counter, String owner) {
        AlertMessage alertMessage = new AlertMessage(counter, owner);
        return buildMessageString(alertMessage);
    }

    public static String buildResumeAlertMessage(AlertLogCounter counter, String owner) {
        AlertMessage alertMessage = new AlertMessage(counter, owner, new Date());
        return buildMessageString(alertMessage);
    }

    public static Map<String, Object> getTemplateAlertMapParams(AlertLogCounter counter, String owner) {
        AlertMessage alertMessage = new AlertMessage(counter, owner);
        return getTemplateAlertMapParams0(alertMessage);
    }

    public static Map<String, Object> getResumeTemplateAlertMapParams(AlertLogCounter counter, String owner) {
        AlertMessage alertMessage = new AlertMessage(counter, owner, new Date());
        return getTemplateAlertMapParams0(alertMessage);
    }

    public static String buildMsgAlertMessage(AlertLogCounter counter, String owner) {
        AlertMessage alertMessage = new AlertMessage(counter, owner);
        return buildMsgMessageString(alertMessage);
    }

    public static String buildMsgResumeAlertMessage(AlertLogCounter counter, String owner) {
        AlertMessage alertMessage = new AlertMessage(counter, owner, new Date());
        return buildMsgMessageString(alertMessage);
    }

    /**
     * 获取告警的alertData
     * @param counter counter
     * @param group 机房名称
     * @return AlarmData
     */
    public static AlertData.AlarmData buildAlertAlarmData(AlertLogCounter counter, String group) {
        return AlertData.AlarmData.builder()
                .eventid(buildEventId(counter))
                .alarmTime(FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS").format(counter.getUpdateTime()))
                .app(counter.getAlertLog().getService())
                .host(String.join(",", counter.getHosts()))
                .idc(group)
                .message(counter.getAlertLog().getMessage())
                .msgType(RESUME_PROBLEM)
                .recoveryTime(null)
                .rule(counter.getRule().getRuleUuid() + "@" + JSONObject.toJSONString(counter.getRule()))
                .alertRuleIdArr(new JSONArray(Lists.newArrayList(counter.getRule().getRuleUuid())))
                .source(ALERT_APP_TYPE_LOG)
                .type(ALERT_HARDWARE_TYPE_APP)
                .build();
    }

    /**
     * 获取告警的alertData
     * @param counter counter
     * @param group 机房名称
     * @return AlarmData
     */
    public static AlertData.AlarmData buildResumeAlarmData(AlertLogCounter counter, String group) {
        return AlertData.AlarmData.builder()
                .eventid(buildEventId(counter))
                .alarmTime(FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS").format(counter.getUpdateTime()))
                .app(counter.getAlertLog().getService())
                .host(counter.getAlertLog().getHostname())
                .idc(group)
                .message(counter.getAlertLog().getMessage())
                .msgType(RESUME_OK)
                .recoveryTime(FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()))
                .rule(counter.getRule().getRuleUuid() + "@" + JSONObject.toJSONString(counter.getRule()))
                .alertRuleIdArr(new JSONArray(Lists.newArrayList(counter.getRule().getRuleUuid())))
                .source(ALERT_APP_TYPE_LOG)
                .type(ALERT_HARDWARE_TYPE_APP)
                .build();
    }

    private static String buildEventId(AlertLogCounter counter) {
        return counter.counterKey() + "-" + FastDateFormat.getInstance("yyyyMMddHHmmss").format(counter.getStartTime());
    }

    private static Map<String, Object> getTemplateAlertMapParams0(AlertMessage alertMessage) {
        String allNodeCount = String.valueOf(alertMessage.getAllNodeCount());
        String errorNodeCount = String.valueOf(alertMessage.getErrorNodeCount());
        String allPodCount = String.valueOf(alertMessage.getAllPodCount());
        String errorPodCount = String.valueOf(alertMessage.getErrorPodCount());
        String service = alertMessage.getService();  /*告警服务*/
        String env = alertMessage.getRule().getEnv(); /*env*/
        String subEnv = alertMessage.getRule().getSubEnv(); /*subEnv*/
        String hosts = alertMessage.getHosts();
        String pods = alertMessage.getPods();
        String level = alertMessage.getLevel(); /*告警级别*/
        String errorCode = StringUtils.getIfEmpty(alertMessage.getRule().getErrorCode(), () -> "无"); /*错误码*/
        String errorDesc = StringUtils.getIfEmpty(alertMessage.getRule().getErrorDesc(), () -> "无"); /*异常说明*/
        String repairSteps = StringUtils.getIfEmpty(alertMessage.getRule().getRepairSteps(), () -> "无"); /*处置预案*/
        String remark = StringUtils.getIfEmpty(alertMessage.getRule().getRemark(), () -> "无"); /*备注*/
        String owner = alertMessage.getOwner(); /*负责人员*/
        String startTime = alertMessage.getStartTime(); /*开始时间*/
        String updateTime = alertMessage.getUpdateTime(); /*更新时间*/
        String resumeDate = StringUtils.getIfEmpty(alertMessage.getResumeDate(), () -> "未恢复"); /*恢复时间*/
        String alertTimesInSchedule = String.valueOf(alertMessage.getAlertTimesInSchedule()); /*周期内告警次数*/
        String alertTimesInAllCycle = String.valueOf(alertMessage.getAlertTimesInAllCycle()); /*全周期内告警总数*/
        String message = alertMessage.getMessage();

        Map<String, Object> result = Maps.newConcurrentMap();
        result.put("allNodeCount", allNodeCount);
        result.put("errorNodeCount", errorNodeCount);
        result.put("allPodCount", allPodCount);
        result.put("errorPodCount", errorPodCount);
        result.put("service", service);
        result.put("env", env);
        result.put("subEnv", StringUtils.isNotBlank(subEnv) ? subEnv : "");

        result.put("hosts", hosts);
        result.put("pods", pods);
        result.put("level", level);
        result.put("errorCode", errorCode);
        result.put("errorDesc", errorDesc);
        result.put("repairSteps", repairSteps);
        result.put("remark", remark);
        result.put("owner", owner);
        result.put("startTime", startTime);
        result.put("updateTime", updateTime);
        result.put("resumeDate", resumeDate);
        result.put("alertTimesInSchedule", alertTimesInSchedule);
        result.put("alertTimesInAllCycle", alertTimesInAllCycle);
        result.put("message", message);

        return result;
    }

    @NotNull
    private static String buildMessageString(AlertMessage alertMessage) {
        StringBuilder builder = new StringBuilder();
        builder.append("告警服务：%s\n");
        builder.append("涉及主机：%s-[%s]\n");
        builder.append("告警级别：%s\n");
        builder.append("异常说明：（错误码：%s）-%s\n");
        builder.append("处置预案：%s\n");
        builder.append("告警备注：%s\n");
        builder.append("负责人员：%s\n");
        builder.append("开始时间：%s\n");
        builder.append("更新时间：%s\n");
        builder.append("是否恢复：%s\n");
        builder.append("告警内容：%s");

        String nodeCount = alertMessage.getAllNodeCount() > 0 ? String.format("(%d/%d)", alertMessage.getErrorNodeCount(), alertMessage.getAllNodeCount()) : EMPTY;
        String podCount = alertMessage.getAllPodCount() > 0 ? String.format("(%d/%d)", alertMessage.getErrorPodCount(), alertMessage.getAllPodCount()) : EMPTY;

        StringBuilder out = new StringBuilder();
        try (Formatter formatter = new Formatter(out)) {
            formatter.format(builder.toString(),
                    alertMessage.getService(),  /*告警服务*/
                    alertMessage.getRule().getEnv() + (StringUtils.isNotBlank(alertMessage.getRule().getSubEnv()) ? String.format("(%s)", alertMessage.getRule().getSubEnv()) : ""), /*env*/
                    nodeCount + alertMessage.getHosts() + (StringUtils.isNotBlank(alertMessage.getPods()) ? "(pods: " + podCount + alertMessage.getPods() + ")" : ""), /*涉及主机*/
                    alertMessage.getLevel(), /*告警级别*/
                    StringUtils.getIfEmpty(alertMessage.getRule().getErrorCode(), () -> "无"), /*错误码*/
                    StringUtils.getIfEmpty(alertMessage.getRule().getErrorDesc(), () -> "无"), /*异常说明*/
                    StringUtils.getIfEmpty(alertMessage.getRule().getRepairSteps(), () -> "无"), /*处置预案*/
                    StringUtils.getIfEmpty(alertMessage.getRule().getRemark(), () -> "无"),
                    alertMessage.getOwner(), /*负责人员*/
                    alertMessage.getStartTime(),  /*开始时间*/
                    alertMessage.getUpdateTime(), /*更新时间*/
                    Objects.isNull(alertMessage.getResumeDate()) ? "未恢复"
                            : "已恢复（周期内告警次数：" + alertMessage.getAlertTimesInSchedule() + "，恢复时间：" + alertMessage.getResumeDate() + "）",  /*是否恢复*/
                    alertMessage.getMessage());  /*异常消息*/
        } catch (Exception e) {
            LOGGER.error("构建告警消息失败。", e);
        }

        return out.toString();
    }

    @NotNull
    private static String buildMsgMessageString(AlertMessage alertMessage) {
        StringBuilder builder = new StringBuilder();
        builder.append("%s(%d条)"); /*告警服务&条数*/
        builder.append(" [%s-%s]"); /*hosts*/
        builder.append(" [%s]"); /*负责人*/
        builder.append(" [%s]"); /*是否恢复*/
        builder.append(" [%s]"); /*告警说明*/

        String nodeCount = alertMessage.getAllNodeCount() > 0 ? String.format("(%d/%d)", alertMessage.getErrorNodeCount(), alertMessage.getAllNodeCount()) : EMPTY;

        StringBuilder out = new StringBuilder();
        try (Formatter formatter = new Formatter(out)) {
            formatter.format(builder.toString(),
                    alertMessage.getService(), /*告警服务*/
                    alertMessage.getAlertTimesInAllCycle(),  /*告警服务*/
                    alertMessage.getRule().getEnv() + (StringUtils.isNotBlank(alertMessage.getRule().getSubEnv()) ? String.format("(%s)", alertMessage.getRule().getSubEnv()) : ""), /*env*/
                    nodeCount,  /*hosts*/
                    alertMessage.getOwner(),  /*负责人*/
                    Objects.isNull(alertMessage.getResumeDate()) ? "未恢复" : "恢复时间：" + alertMessage.getResumeDate() + "）",  /*是否恢复*/
                    StringUtils.getIfEmpty(alertMessage.getRule().getErrorDesc(), () -> alertMessage.getAlertName())); /*告警说明*/

        } catch (Exception e) {
            LOGGER.error("构建告警消息失败。", e);
        }
        return out.toString();
    }
}
